import * as vscode from 'vscode';
import { Task, TaskGroup, TaskStatus, TaskTag } from '../models/todo';

export interface TodoState {
    tasks: Task[];
    groups: TaskGroup[];
}

export class TodoStateService {
    private tasks: Task[] = [];
    private groups: TaskGroup[] = [];

    constructor(private context: vscode.ExtensionContext) {
        this.loadState();
    }

    private loadState() {
        const state = this.context.globalState.get<TodoState>('todoState');
        if (state) {
            this.tasks = state.tasks;
            this.groups = state.groups;
        }
    }

    private saveState() {
        this.context.globalState.update('todoState', {
            tasks: this.tasks,
            groups: this.groups,
        });
    }

    // Task operations
    async createTask(title: string, groupId?: string): Promise<Task> {
        const task: Task = {
            id: Date.now().toString(),
            title,
            status: TaskStatus.Pending,
            groupId,
            createdAt: Date.now(),
            updatedAt: Date.now(),
            order: this.tasks.length,
        };

        this.tasks.push(task);
        this.saveState();
        return task;
    }

    async createGroup(name: string): Promise<TaskGroup> {
        const group: TaskGroup = {
            id: Date.now().toString(),
            name,
            tasks: [],
            createdAt: Date.now(),
            updatedAt: Date.now(),
            order: this.groups.length,
        };

        this.groups.push(group);
        this.saveState();
        return group;
    }

    async deleteTask(taskId: string): Promise<void> {
        this.tasks = this.tasks.filter((t) => t.id !== taskId);
        this.saveState();
    }

    async deleteGroup(groupId: string): Promise<void> {
        this.groups = this.groups.filter((g) => g.id !== groupId);
        this.tasks = this.tasks.filter((t) => t.groupId !== groupId);
        this.saveState();
    }

    async updateTaskStatus(taskId: string, status: TaskStatus): Promise<Task | undefined> {
        const task = this.tasks.find((t) => t.id === taskId);
        if (task) {
            task.status = status;
            task.updatedAt = Date.now();
            this.saveState();
            return task;
        }
        return undefined;
    }

    async updateTaskTag(taskId: string, tag: TaskTag): Promise<Task | undefined> {
        const task = this.tasks.find((t) => t.id === taskId);
        if (task) {
            task.tag = tag;
            task.updatedAt = Date.now();
            this.saveState();
            return task;
        }
        return undefined;
    }

    async moveTask(taskId: string, targetGroupId: string | null): Promise<Task | undefined> {
        const task = this.tasks.find((t) => t.id === taskId);
        if (task) {
            task.groupId = targetGroupId || undefined;
            task.updatedAt = Date.now();
            this.saveState();
            return task;
        }
        return undefined;
    }

    async reorderTask(taskId: string, targetTaskId: string | null): Promise<void> {
        const sourceTask = this.tasks.find((t) => t.id === taskId);
        if (!sourceTask) return;

        const tasksInSameGroup = this.tasks.filter(
            (t) => t.groupId === sourceTask.groupId
        );
        const currentIndex = tasksInSameGroup.findIndex((t) => t.id === taskId);
        const targetIndex = targetTaskId
            ? tasksInSameGroup.findIndex((t) => t.id === targetTaskId)
            : tasksInSameGroup.length;

        if (currentIndex === -1) return;

        const [movedTask] = tasksInSameGroup.splice(currentIndex, 1);
        tasksInSameGroup.splice(
            targetIndex > currentIndex ? targetIndex - 1 : targetIndex,
            0,
            movedTask
        );

        tasksInSameGroup.forEach((task, index) => {
            task.order = index;
        });

        this.tasks = this.tasks.map((task) => {
            const updatedTask = tasksInSameGroup.find((t) => t.id === task.id);
            return updatedTask || task;
        });

        this.saveState();
    }

    async reorderGroup(groupId: string, targetGroupId: string | null): Promise<void> {
        const sourceGroup = this.groups.find((g) => g.id === groupId);
        if (!sourceGroup) return;

        const currentIndex = this.groups.findIndex((g) => g.id === groupId);
        const targetIndex = targetGroupId
            ? this.groups.findIndex((g) => g.id === targetGroupId)
            : this.groups.length;

        if (currentIndex === -1) return;

        const [movedGroup] = this.groups.splice(currentIndex, 1);
        this.groups.splice(
            targetIndex > currentIndex ? targetIndex - 1 : targetIndex,
            0,
            movedGroup
        );

        this.groups.forEach((group, index) => {
            group.order = index;
        });

        this.saveState();
    }

    async updateGroupName(groupId: string, newName: string): Promise<TaskGroup | undefined> {
        const group = this.groups.find((g) => g.id === groupId);
        if (group) {
            group.name = newName;
            group.updatedAt = Date.now();
            this.saveState();
            return group;
        }
        return undefined;
    }

    // Getters
    getTasks(): Task[] {
        return this.tasks;
    }

    getGroups(): TaskGroup[] {
        return this.groups;
    }

    getTasksStats() {
        const stats = {
            total: this.tasks.length,
            pending: 0,
            inProgress: 0,
            done: 0,
            cancelled: 0,
        };

        this.tasks.forEach((task) => {
            switch (task.status) {
                case TaskStatus.Pending:
                    stats.pending++;
                    break;
                case TaskStatus.InProgress:
                    stats.inProgress++;
                    break;
                case TaskStatus.Done:
                    stats.done++;
                    break;
                case TaskStatus.Cancelled:
                    stats.cancelled++;
                    break;
            }
        });

        return stats;
    }
}